﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace Dycox.Validation
{
    [Serializable]
    public class RangeValidator : Validator
    {
        public RangeValidator()
        {

        }

        private object _lowerBound;

        public object LowerBound
        {
            get { return _lowerBound; }
            set
            {
                if (value == null)
                    throw new ArgumentNullException("LowerBound");
                if (_upperBound != null && _upperBound.GetType() != value.GetType())
                    throw new ArgumentException("The type of LowerBound must match UpperBound>");
                _lowerBound = value;
            }
        }

        private object _upperBound;

        public object UpperBound
        {
            get { return _upperBound; }
            set
            {
                if (value == null)
                    throw new ArgumentNullException("UpperBound");
                if (_lowerBound != null && _lowerBound.GetType() != value.GetType())
                    throw new ArgumentException("The type of UpperBound must match LowerBound.");
                _upperBound = value;
            }
        }

        private IComparer _comparer;

        public IComparer Comparer
        {
            get { return _comparer; }
            set { _comparer = value; }
        }

        private bool _excludeBoundValues;
        [DefaultValue(false)]
        public bool ExcludeBoundValues
        {
            get { return _excludeBoundValues; }
            set { _excludeBoundValues = value; }
        }

        protected internal override ValidationResult IsValid(object value, PropertyValidationContext context)
        {
            if (value == null) return ValidationResult.Ignore;
            if (_upperBound == null || _lowerBound == null)
                throw new InvalidOperationException("Either LowerBound or UpperBound not specified.");

            value = Dycox.Utils.ConvertUtil.ConvertType(value, _lowerBound.GetType());

            int diff1, diff2;
            if (_comparer != null)
            {
                diff1 = _comparer.Compare(_lowerBound, value);
                diff2 = _comparer.Compare(_upperBound, value);
            }
            else if (_upperBound is IComparable)
            {
                diff1 = ((IComparable)_lowerBound).CompareTo(value);
                diff2 = ((IComparable)_upperBound).CompareTo(value);
            }
            else
                throw new InvalidOperationException("The Comparer property not set.");

            bool ok;
            if (_excludeBoundValues)
            {
                ok = diff1 < 0 && diff2 > 0;
            }
            else
            {
                ok = diff1 <= 0 && diff2 >= 0;
            }

            return ok ? ValidationResult.Valid : ValidationResult.Invalid;
        }
    }

}
